/**
 * This class embodies a panel for specifying and putting Orb updates. 
 */
package org.hackystat.ui.orb.client;

import java.util.Date;

import org.hackystat.ui.orb.client.common.AmbientOrb;
import org.hackystat.ui.orb.client.common.AnimationsEnum;
import org.hackystat.ui.orb.client.common.ColorsEnum;

import com.google.gwt.user.client.Cookies;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FocusListener;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;

/**
 * This class embodies a panel for specifying and putting Orb updates. 
 * @author David J. Nickles
 *
 */
public class SettingsPanel extends Composite implements ClickListener, FocusListener {
  
  private ListBox colorListBox;
  private ListBox animListBox;
  private TextBox devIdTextBox;
  private TextBox commentTextBox;
  private Image statusImage;
  private HTML statusLabel;

  /**
   * Creates a GeneratorPanel.
   */
  public SettingsPanel() {
    
    VerticalPanel vp = new VerticalPanel();

    Grid statusGrid = new Grid(1, 2);
    statusGrid.setWidget(0, 0, this.statusImage = new Image(Images.WAIT_IMAGE));
    this.statusImage.setSize("20px", "20px"); 
    this.statusImage.setVisible(false);
    statusGrid.setWidget(0, 1, this.statusLabel = new HTML());
    this.statusLabel.setStyleName(Styles.SMALLLABELSTYLE);
    vp.add(statusGrid);
    
    Grid grid = new Grid(5, 2);
    grid.setWidget(0, 0, new Label("Color:"));
    grid.setWidget(0, 1, this.colorListBox = new ListBox());
    ColorsEnum[] colors = ColorsEnum.toArray();
    for (int i = 0; i < colors.length; i++) {
      colorListBox.addItem(colors[i].getName());
    }

    grid.setWidget(1, 0, new Label("Animation:"));
    grid.setWidget(1, 1, this.animListBox = new ListBox());
    AnimationsEnum[] animations = AnimationsEnum.toArray();
    for (int i = 0; i < animations.length; i++) {
      animListBox.addItem(animations[i].getName());
    }

    grid.setWidget(2, 0, new Label("Device ID:"));
    Date cookieExpires = new Date((new Date()).getTime() + (1000L * 60L * 60L * 24L * 365L));
    VerticalPanel row3 = new VerticalPanel();
    row3.add(this.devIdTextBox = new TextBox());
    String passwordCookie = Cookies.getCookie("devID");
    if (passwordCookie == null) {
      this.devIdTextBox.setText("");
      Cookies.setCookie("devID", this.devIdTextBox.getText(), cookieExpires);
    }
    else {
      this.devIdTextBox.setText(passwordCookie);
    }
    this.devIdTextBox.addFocusListener(this);
    Label devIdLabel = new Label("Example: ABC-45F-GHI");
    devIdLabel.setStyleName(Styles.EXAMPLELABELSTYLE);
    row3.add(devIdLabel);
    grid.setWidget(2, 1, row3);
    
    grid.setWidget(3, 0, new Label("Comment:"));
    grid.setWidget(3, 1, this.commentTextBox = new TextBox());

    Button submit = new Button("Submit");
    grid.setWidget(4, 1, submit);
    submit.addClickListener(this);
    submit.setStyleName(Styles.BLACKBUTTONSTYLE);

    vp.add(grid);
    initWidget(vp);
  }

  /**
   * This method responds to users clicking the Submit button.
   * @param sender the widget clicked.
   */
  public void onClick(Widget sender) {
    rpcPutProject();
  }
  
  /**
   * This method sets the state of the host uri validation.
   * @param state Boolean represents the state of the user valid=true, invalid=false
   */
  public void processPutOrbResult(String state) {
    this.statusImage.setVisible(false);
    String time = DateTimeFactories.getInstance().getBodyfactory().format(new Date());
    if (Boolean.TRUE.toString().equals(state)) {
      this.statusLabel.setHTML("Orb update sent successfully at " + time + "<br />with: "  
        + this.colorListBox.getItemText(this.colorListBox.getSelectedIndex()) + ", "
        + this.animListBox.getItemText(this.animListBox.getSelectedIndex()) + ", "
        + this.devIdTextBox.getText() + ", " + this.commentTextBox.getText());
      this.statusLabel.setStyleName(Styles.VALIDLABELSTYLE);
    }
    else {
      this.statusLabel.setHTML("Orb update error reported at " + time + "<br />" + state);
      this.statusLabel.setStyleName(Styles.INVALIDLABELSTYLE);
    }
  }
  
  /**
   * Invoke NewProject on the servlet.
   */
  public void rpcPutProject() {
    this.statusImage.setVisible(true);
    this.statusLabel.setText("Sending Orb update: " 
      + this.colorListBox.getItemText(this.colorListBox.getSelectedIndex()) + ", "
      + this.animListBox.getItemText(this.animListBox.getSelectedIndex()) + ", "
      + this.devIdTextBox.getText() + ", " + this.commentTextBox.getText());
    this.statusLabel.setStyleName(Styles.EXAMPLELABELSTYLE);
    RPCServiceFactory.getInstance().getService().putOrb(new AmbientOrb(this.devIdTextBox.getText(), 
      ColorsEnum.valueOf(this.colorListBox.getItemText(
        this.colorListBox.getSelectedIndex())).getOrdinal(),
      AnimationsEnum.valueOf(this.animListBox.getItemText(
        this.animListBox.getSelectedIndex())).getOrdinal(),
      this.commentTextBox.getText()),
      new AsyncCallback()
      {
        public void onSuccess(Object result) {
          processPutOrbResult((String) result);
        }

        public void onFailure(Throwable caught) {
          if (caught instanceof com.google.gwt.user.client.rpc.InvocationException) {
            log(RPCServiceFactory.PRCERRORNAME, "Cannot invoke user validation on servlet.");
          } 
          else {
            log(RPCServiceFactory.PRCERRORNAME, caught.toString());
          }
        }
      });
  }  
  
  /**
   * Log this message in the reader display.
   * @param header the message header or subject
   * @param body the message body
   */
  public void log(String header, String body) {
    Window.alert(header + " : " + body);
  }


  /** 
   * Called when any registered settings fields gain focus.
   * @param sender the UI widget that is losing focus.
   */
  public void onFocus(Widget sender) {
    // TODO Auto-generated method stub
    
  }


  /** 
   * When any of the settings fields lose focus then check to see if the information is valid.
   * @param sender the UI widget that is losing focus.
   */
  public void onLostFocus(Widget sender) {
    if (sender.equals(this.devIdTextBox)) {
      Date cookieExpires = new Date((new Date()).getTime() + (1000L * 60L * 60L * 24L * 365L));
      Cookies.setCookie("devID", this.devIdTextBox.getText(), cookieExpires);
    }
  }
}
